package com.tianji.learning.utils;

import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;

/*
 *   Description 优化学习记录的延迟任务
 *   @author zhangyan
 *   @time   2024/12/11
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class LearningRecordDelayTaskHandler {

    private final StringRedisTemplate redisTemplate;
    private final LearningRecordMapper recordMapper;
    private final ILearningLessonService lessonService;
    private final DelayQueue<DelayTask<RecordTaskData>> queue = new DelayQueue<>();
    private final static String RECORD_KEY_TEMPLATE = "learning:record:{}";
    private static volatile boolean begin = true;

    @PostConstruct
    public void init() {
        CompletableFuture.runAsync(this::handleDelayTask);
    }

    @PreDestroy
    public void destory() {
        begin = false;
        log.debug("延迟任务停止执行");
    }

    @Async("taskExecutor")
    public void handleDelayTask() {
        while (begin) {
            try {
                //1 获取到期的延迟任务
                DelayTask<RecordTaskData> task = queue.take();
                RecordTaskData data = task.getData();
                //2查询redis缓存
                LearningRecord record = readRecordCache(data.getLessonId(), data.getSectionId());
                if (record == null) {
                    continue;
                }
                //3 比较数据 , moment值
                if (!ObjectUtils.equals(data.getMoment(), record.getMoment())) {
                    //不一致,说明还在持续播放视频,放弃旧数据
                    continue;
                }
                //4.一致,持久化数据到数据库
                //4.1 更新学习记录的moment
                record.setFinished(null);
                recordMapper.updateById(record);
                //4.2 跟新课表的学习进度
                LearningLesson lesson = new LearningLesson();
                lesson.setId(data.getLessonId());
                lesson.setLatestSectionId(data.getSectionId());
                lesson.setLatestLearnTime(LocalDateTime.now());
                lessonService.updateById(lesson);
            } catch (Exception e) {
                log.error("延迟任务处理异常", e);
            }
        }
    }

    /**
     * 添加延迟任务(包含添加跟新缓存)
     * @param record
     */
    public void addLearningRecordTask(LearningRecord record) {
        //1.添加或更新数据到redis缓存
        wirteRecondCache(record);
         //提交任务到延迟队列 DelayQueue 延迟时间20秒
        queue.add(new DelayTask<>(new RecordTaskData(record), Duration.ofSeconds(20)));
    }

    /**
     * 添加更新缓存
     * @param record
     */
    public void wirteRecondCache(LearningRecord record){
        log.debug("添加延迟任务到redis缓存");

        try {
            //数据转换
            String jsonStr = JsonUtils.toJsonStr(record);
            //设置redis的key
            String key= StringUtils.format(RECORD_KEY_TEMPLATE, record.getLessonId());
            redisTemplate.opsForHash().put(key, record.getSectionId().toString(), jsonStr);
            //设置过期时间
            redisTemplate.expire(key, Duration.ofSeconds(60));
        } catch (Exception e) {
            log.error("添加延迟任务到redis缓存异常", e);
        }
    }

    /**
     * 读取缓存
     * @param lessonId
     * @param sectionId
     * @return
     */
    public LearningRecord readRecordCache(Long lessonId,Long sectionId) {
        try {
            //读取redis数据
            String key= StringUtils.format(RECORD_KEY_TEMPLATE, lessonId);
            Object cacheData = redisTemplate.opsForHash().get(key, sectionId.toString());
            if (ObjectUtils.isEmpty(cacheData)){
                return null;
            }
            //转换数据
            return JsonUtils.toBean(cacheData.toString(), LearningRecord.class);
        } catch (Exception e) {
            log.error("读取redis缓存异常", e);
            return null;
        }
    }

    /**
     * 清除缓存
     * @param lessonId
     * @param sectionId
     */
    public void cleanRecordCache(Long lessonId,Long sectionId){
        String key= StringUtils.format(RECORD_KEY_TEMPLATE, lessonId);
        redisTemplate.opsForHash().delete(key, sectionId.toString());
    }
    @Data
    @NoArgsConstructor
    private static class RecordCacheData {
        private Long id;
        private Integer moment;
        private Boolean finished;

        public RecordCacheData(LearningRecord record) {
            this.id = record.getId();
            this.moment = record.getMoment();
            this.finished = record.getFinished();
        }
    }

    @Data
    @NoArgsConstructor
    private static class RecordTaskData {
        private Long lessonId;
        private Long sectionId;
        private Integer moment;

        public RecordTaskData(LearningRecord record) {
            this.lessonId = record.getLessonId();
            this.sectionId = record.getSectionId();
            this.moment = record.getMoment();
        }
    }
}
